/*global analogue*/
/*jslint indent: 4*/

/*Analogue.Ajax 1.11.12, Copyright (c) 2011 Analogue Web Design LLC, all rights reserved.*/
analogue.extend((function (document, push, window, $) {
    'use strict';

    var build = new Date(1323831486346),

        guid = 1E3,

        inject = function (json) {
            var cleanup = function (callback, script) {
                    try {
                        delete window[callback];
                    } catch (e) {
                        window[callback] = null;
                    }
                    script.remove();
                },
                script = $('<script/>'),
                timeoutId = window.setTimeout(function () {
                    if (typeof json.failure === 'function') {
                        json.failure.call(json.context, new Error('Request Timeout'), 408, 'Request Timeout');
                    }
                    cleanup(json.callback, script);
                }, json.timeout || 1E4);
            if (json.parameters) {
                json.url += (json.url.indexOf('?') > -1 ? '&' : '?') + json.parameters;
            }
            window[json.callback] = function (response) {
                window.clearTimeout(timeoutId);
                if (typeof json.success === 'function') {
                    json.success.call(json.context, response, 200, 'OK');
                }
                cleanup(json.callback, script);
            };
            script.set({
                async: true,
                src: json.url,
                type: 'text/javascript'
            }).insertBefore($('script')[0]);
            return this;
        },

        request = function (ajax) {
            var aborted = false,
                done = false,
                i,
                response = '',
                status,
                statusText = '',
                timeoutId = null,
                xhr = new window.XMLHttpRequest();
            if (xhr) {
                if (ajax.method === 'GET' && ajax.parameters !== null) {
                    ajax.url += (ajax.url.indexOf('?') > -1 ? '&' : '?') + ajax.parameters;
                    ajax.parameters = null;
                }
                if (ajax.username) {
                    xhr.open(ajax.method, ajax.url, ajax.async, ajax.username, ajax.password);
                } else {
                    xhr.open(ajax.method, ajax.url, ajax.async);
                }
                xhr.setRequestHeader('AJAX', 'true');
                xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                if (ajax.method === 'POST') {
                    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
                    xhr.setRequestHeader('Content-length', ajax.parameters ? ajax.parameters.length : 0);
                    if (xhr.overrideMimeType) {
                        xhr.setRequestHeader('Connection', 'close');
                    }
                }
                if (ajax.responseType === 'json') {
                    xhr.setRequestHeader('Accept', 'application/json, text/javascript, */*');
                } else {
                    xhr.setRequestHeader('Accept', 'text/javascript, text/html, application/xml, text/xml, text/plain, */*');
                }
                for (i in ajax.headers) {
                    if (ajax.headers.hasOwnProperty(i) && i === 'string') {
                        xhr.setRequestHeader(i, ajax.headers[i]);
                    }
                }
                if (typeof ajax.success === 'function') {
                    xhr.onreadystatechange = function () {
                        /*jslint evil: true, regexp: true*/
                        try {
                            if (xhr.readyState === 4 && !done) {
                                window.clearTimeout(timeoutId);
                                done = true;
                                status = xhr.status;
                                if (status === 1223) {
                                    status = 204;
                                }
                                statusText = xhr.statusText;
                                if ((status || document.location.protocol !== 'file:') && (status < 200 || status >= 300)) {
                                    throw new Error(statusText);
                                }
                                response = /xml/i.test(ajax.responseType) ? xhr.responseXML : xhr.responseText;
                                if (/json/i.test(ajax.responseType) && !!response) {
                                    if (typeof JSON === 'object' && typeof JSON.parse === 'function') {
                                        response = JSON.parse(response);
                                    } else if (/^[\],:{}\s]*$/.test(response
                                                       .replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
                                                       .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
                                                       .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
                                        response = eval('(' + response + ')');
                                    } else {
                                        throw new Error('Invalid JSON: ' + response);
                                    }
                                }
                                xhr.onreadystatechange = function () {};
                                xhr = null;
                                ajax.success.call(ajax.context, response, status, statusText);
                            } else {
                                if (typeof ajax.loading === 'function') {
                                    ajax.loading.call(ajax.context, xhr.readyState);
                                }
                            }
                        } catch (e) {
                            if (!aborted) {
                                window.clearTimeout(timeoutId);
                                done = true;
                                if (xhr) {
                                    status = xhr.status;
                                    try {
                                        statusText = xhr.statusText;
                                    } catch (ex) {}
                                    xhr.onreadystatechange = function () {};
                                    xhr = null;
                                } else {
                                    status = 200;
                                    statusText = 'OK';
                                }
                                if (typeof ajax.failure === 'function') {
                                    ajax.failure.call(ajax.context, e, status, statusText);
                                }
                            }
                        }
                    };
                }
                xhr.send(ajax.parameters);
                if (ajax.timeout) {
                    timeoutId = window.setTimeout(function () {
                        if (!done) {
                            aborted = true;
                            xhr.abort();
                            done = true;
                            status = 408;
                            statusText = 'Request Timeout';
                            xhr.onreadystatechange = function () {};
                            xhr = null;
                            if (typeof ajax.failure === 'function') {
                                ajax.failure.call(ajax.context, new Error(statusText), status, statusText);
                            }
                        }
                    }, ajax.timeout);
                }
            }
            return this;
        },

        serialize = function (object) {
            var field,
                fields,
                i,
                ii,
                j,
                jj,
                k,
                parameters = [],
                push = function (name, value) {
                    parameters.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
                };
            if (object.nodeType === 1) {
                fields = object.elements;
                for (i = 0, ii = fields.length; i < ii; i += 1) {
                    field = fields[i];
                    if (field.name && !field.disabled) {
                        if (/^(?:checkbox|radio)$/i.test(field.type) && field.checked) {
                            push(field.name, field.value);
                        } else if (field.type === 'select-one' && field.selectedIndex >= 0) {
                            push(field.name, field.options[field.selectedIndex].value);
                        } else if (field.type === 'select-multiple') {
                            for (j = 0, jj = field.options.length; j < jj; j += 1) {
                                if (field.options[j].selected) {
                                    push(field.name, field.options[j].value);
                                }
                            }
                        } else if (/^(?:color|date|datetime|email|hidden|month|number|password|range|search|submit|tel|text|textarea|time|url|week)$/i.test(field.type)) {
                            push(field.name, field.value);
                        }
                    }
                }
            } else if (typeof object === 'object') {
                for (k in object) {
                    if (object.hasOwnProperty(k)) {
                        push(k, object[k]);
                    }
                }
            }
            return parameters;
        },

        versioning = [1, String(build.getFullYear()).slice(2), String((build.getMonth() + 1) / 100).slice(2)];

    function init(method, url, settings, form) {
        var instance,
            parameters = [];
        settings = typeof settings === 'function' ? {
            success: settings
        } : settings || {};
        if (form) {
            settings.context = form;
            push.apply(parameters, serialize(form));
        }
        if (settings.nocache && method === 'GET') {
            parameters.push('nocache=' + new Date().getTime());
        }
        if (settings.parameters) {
            push.apply(parameters, serialize(settings.parameters));
        }
        if (settings.responseType === 'jsonp' && settings.callbackParameter !== false) {
            settings.callback = settings.callback || 'jsonp' + (guid += 1);
            parameters.push((settings.callbackParameter || 'callback') + '=' + settings.callback);
        }
        instance = {
            async: settings.async || true,
            callback: settings.callback || null,
            context: settings.context ? (typeof settings.context === 'string' ? $(settings.context)[0] : settings.context[0] || settings.context) : null,
            failure: settings.failure || null,
            headers: settings.headers || {},
            loading: settings.loading || null,
            method: method,
            parameters: parameters.length > 0 ? parameters.join('&') : null,
            password: settings.password || null,
            responseType: settings.responseType || 'text',
            success: settings.success || null,
            timeout: settings.timeout || null,
            url: url,
            username: settings.username || null
        };
        if (settings.responseType === 'jsonp') {
            return inject(instance);
        }
        return request(instance);
    }

    return {
        init: function () {
            $.ajax = {
                get: function (url, settings) {
                    return init('GET', url, settings);
                },
                post: function (url, settings) {
                    return init('POST', url, settings);
                },
                version: versioning.join('.') + ' (' + parseInt(build.valueOf() / 1E3, 10) + ')'
            };
            return this;
        },
        submit: function (settings) {
            if (this.tagName !== 'FORM') {
                throw new Error('Invalid Element: ' + this.tagName);
            }
            return init(this[0].method.toUpperCase(), this[0].action, settings, this[0]);
        }
    };
}(this.document, [].push, this, analogue)));